package xin.tianhui.cloud.weblog.service.impl;

import xin.tianhui.cloud.weblog.model.dto.ArticleResultDTO;
import xin.tianhui.cloud.weblog.model.dto.ArticleAlterDTO;
import xin.tianhui.cloud.weblog.model.dto.ArticleAttrResultDTO;
import xin.tianhui.cloud.weblog.model.dto.ArticleQueryDTO;
import xin.tianhui.cloud.weblog.model.dto.ArticleTxtResultDTO;
import xin.tianhui.cloud.weblog.model.dto.ArticleTypeResultDTO;
import xin.tianhui.cloud.weblog.model.dto.ChannelResultDTO;
import xin.tianhui.cloud.weblog.model.dto.ModelItemQueryDTO;
import xin.tianhui.cloud.weblog.model.dto.ModelItemResultDTO;
import xin.tianhui.cloud.weblog.model.po.Article;
import xin.tianhui.cloud.weblog.model.po.ArticleAttr;
//import xin.tianhui.cloud.weblog.model.po.ArticleAttr;
import xin.tianhui.cloud.weblog.model.po.ArticleType;
import xin.tianhui.cloud.weblog.model.po.ArticleTxt;
import xin.tianhui.cloud.weblog.model.po.Channel;
import xin.tianhui.cloud.weblog.constant.Constants;
import xin.tianhui.cloud.weblog.core.model.dto.PagingDTO;
import xin.tianhui.cloud.weblog.core.model.vo.PagingVO;
import xin.tianhui.cloud.weblog.mapper.ArticleMapper;
//import xin.tianhui.cloud.weblog.service.IArticleAttrService;
import xin.tianhui.cloud.weblog.service.IArticleTypeService;
import xin.tianhui.cloud.weblog.service.IArticleAttrService;
import xin.tianhui.cloud.weblog.service.IArticleService;
import xin.tianhui.cloud.weblog.service.IArticleTxtService;
import xin.tianhui.cloud.weblog.service.IChannelService;
import xin.tianhui.cloud.weblog.service.IModelItemService;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.sql.SqlHelper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.dozer.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;



/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author junchen
 * @since 2018-04-07
 */
@CacheConfig(cacheNames="article",keyGenerator="keyGenerator")
@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements IArticleService {
	
	/*@Autowired
	private IArticleAttrService articleAttrService;*/
	
	@Autowired
	private IArticleTypeService articleTypeService;
	
	@Autowired
	private IArticleTxtService articleTxtService;
	
	@Autowired
	private IArticleAttrService articleAttrService;
	
	@Autowired
	private IChannelService channelService;
	
	@Autowired
	private IModelItemService modelItemService;
	
	@Autowired
	private Mapper mapper;
	
	@Cacheable(key="'id:'+#id")
	@Override
	public ArticleResultDTO getArticleById(Integer id) {
		Article article = baseMapper.selectById(id);
		if(article != null) {
			ArticleResultDTO dto = new ArticleResultDTO();
			dto.setBid(article.getId());
			dto.setTitle(article.getTitle());
			dto.setShortTitle(article.getShortTitle());
			dto.setSummary(article.getSummary());
			dto.setAccessNum(article.getAccessNum());
			dto.setReleaseDate(article.getReleaseDate());
			ChannelResultDTO channel = channelService.getChannelById(article.getChannelId());
			dto.setChannel(channel);
			ArticleTypeResultDTO type = articleTypeService.getArticleType(article.getTypeId());
			dto.setArticleType(type);
			ArticleTxtResultDTO txtDto = articleTxtService.getArticleTxt(article.getId());
			dto.setContent(txtDto);
			List<ArticleAttrResultDTO> attrs = articleAttrService.getArticleAttr(article.getId());
			Map<String,String> attr = Optional.ofNullable(attrs).map(result->{
				Map<String,String> map = Maps.newHashMap();
				result.forEach(r->{
					map.put(r.getName(), r.getValue());
				});
				return map;
			}).orElse(Maps.newHashMap());
			dto.setAttr(attr);
			return dto;
		}
		return null;
	}
	
	@Cacheable
	@SuppressWarnings("unchecked")
	@Override
	public PagingVO<ArticleResultDTO> getArticlePage(PagingDTO paging,ArticleQueryDTO queryDto) {
		String sidx = paging.getSidx();
		String sord = paging.getSord();
		String orderByField = null;
		boolean asc = false;
		if(StringUtils.isNotBlank(sidx) && StringUtils.isNotBlank(sord)) {
			if(sidx.equals("accessNum")) {
				orderByField = "access_num";
			}
			if(sidx.equals("releaseDate")) {
				orderByField = "release_date";
			}
			asc  = sord.toUpperCase().equals("ASC");
		}
		Page<Article> page = new Page<>(paging.getPage(), paging.getRows());
		if(asc) {
			page.setAscs(orderByField);
		}else {
			page.setDescs(orderByField);
		}
		Article article = new Article();
		article.setChannelId(queryDto.getChannelBId());
		article.setIsRecommend(queryDto.getIsRecommend());
		QueryWrapper<Article> entityWrapper = new QueryWrapper<>(article);
		Wrapper<Article> wrapper = (Wrapper<Article>) SqlHelper.fillWrapper(page, entityWrapper);
        IPage<Article> articles = baseMapper.selectPage(page, wrapper);
        List<ArticleResultDTO> rows = Optional.ofNullable(articles).map(result->{
        	List<ArticleResultDTO> dtos = Lists.newArrayList();
			result.getRecords().forEach(r->{
				ArticleResultDTO dto = new ArticleResultDTO();
				dto.setBid(r.getId());
				dto.setTitle(r.getTitle());
				dto.setShortTitle(r.getShortTitle());
				dto.setSummary(r.getSummary());
				dto.setAccessNum(r.getAccessNum());
				dto.setReleaseDate(r.getReleaseDate());
				dto.setStatus(r.getStatus());
				
				//ArticleTxt articleTxt = articleTxtService.selectTxtById(r.getId());
				//if(articleTxt != null) {
				//	dto.setContent(articleTxt.getContent());
				//}
				/*List<ArticleAttr> attrs = articleAttrService.selectAttrById(r.getId());
				Map<String,String> attr = Optional.ofNullable(attrs).map(at->{
					Map<String,String> map = Maps.newHashMap();
					at.forEach(a->{
						map.put(a.getName(), a.getValue());
					});
					return map;
				}).orElse(Maps.newHashMap());
				dto.setAttr(attr);*/
				
				ArticleType type = articleTypeService.selectById(r.getTypeId());
				if(type!=null) {
					ArticleTypeResultDTO typeDto = new ArticleTypeResultDTO();
					typeDto.setName(type.getName());
					typeDto.setCode(type.getCode());
					dto.setArticleType(typeDto);
				}
				
				Channel channel = channelService.selectById(r.getChannelId());
				if(channel!=null) {
					ChannelResultDTO channelResultDTO = new ChannelResultDTO();
					channelResultDTO.setBid(channel.getId());
					channelResultDTO.setName(channel.getName());
					channelResultDTO.setPath(channel.getPath());
					dto.setChannel(channelResultDTO);
				}
				
				dtos.add(dto);
			});
        	return dtos;
        }).orElse(Collections.emptyList());
        //page.getPages(), page.getCurrent(), page.getTotal()
        PagingVO<ArticleResultDTO> pagingVO = new PagingVO<>(rows,page.getPages(),page.getCurrent(),page.getTotal());
		return pagingVO;
	}
	
	@Transactional
	@Override
	public ArticleResultDTO insertArticle(ArticleAlterDTO alterDto) {
		Article article = new Article();
		mapper.map(alterDto, article,Constants.MAPPER_ARTICLE_ALTER_ID);
		baseMapper.insert(article);
		ModelItemQueryDTO modelItemQueryDTO = new ModelItemQueryDTO();
		modelItemQueryDTO.setChannelBid(article.getChannelId());
		List<ModelItemResultDTO> itemDTOs = modelItemService.getModelItemList(modelItemQueryDTO);
		Map<String,Object> map = alterDto.getExt();
		if(MapUtils.isNotEmpty(map)){
			Set<String> keys = map.keySet();
			items:for (ModelItemResultDTO item : itemDTOs) {
				if("txt".equals(item.getField())) {
					ArticleTxtResultDTO txtDto = alterDto.getContent();
					if(txtDto!=null) {
						ArticleTxt txt = new ArticleTxt();
						txt.setArticleId(article.getId());
						txt.setHtml(txtDto.getHtml());
						txt.setMarkdown(txtDto.getMarkdown());
						articleTxtService.insert(txt);
					}
					continue items;
				}
				keys:for (String key : keys) {
					String value = MapUtils.getString(map, key);
					if(item.getField().equals(key) && StringUtils.isNotBlank(value)) {
						ArticleAttr attr = new ArticleAttr();
						attr.setArticleId(article.getId());
						attr.setName(key);
						attr.setValue(value);
						articleAttrService.insert(attr);
						continue keys;
					}
				}
			}
		}
		ArticleResultDTO resultDTO = new ArticleResultDTO();
		mapper.map(article, resultDTO,Constants.MAPPER_ARTICLE_ID);
		return resultDTO;
	}
	
	@Transactional
	@Override
	public ArticleResultDTO updateArticle(ArticleAlterDTO alterDto) {
		Article article = new Article();
		mapper.map(alterDto, article,Constants.MAPPER_ARTICLE_ALTER_ID);
		
		baseMapper.updateById(article);
		ModelItemQueryDTO modelItemQueryDTO = new ModelItemQueryDTO();
		modelItemQueryDTO.setChannelBid(article.getChannelId());
		List<ModelItemResultDTO> itemDTOs = modelItemService.getModelItemList(modelItemQueryDTO);
		
		ArticleTxt articleTxt = new ArticleTxt();
		articleTxt.setArticleId(article.getId());
		QueryWrapper<ArticleTxt> wrapper = new QueryWrapper<>(articleTxt);
		articleTxtService.delete(wrapper);
		
		ArticleAttr articleAttr = new ArticleAttr();
		articleAttr.setArticleId(article.getId());
		QueryWrapper<ArticleAttr> attrWrapper = new QueryWrapper<>(articleAttr);
		articleAttrService.delete(attrWrapper);
		
		Map<String,Object> map = alterDto.getExt();
		if(MapUtils.isNotEmpty(map)){
			Set<String> keys = map.keySet();
			items:for (ModelItemResultDTO item : itemDTOs) {
				if("txt".equals(item.getField())) {
					ArticleTxtResultDTO txtDto = alterDto.getContent();
					if(txtDto!=null) {
						ArticleTxt txt = new ArticleTxt();
						txt.setArticleId(article.getId());
						txt.setHtml(txtDto.getHtml());
						txt.setMarkdown(txtDto.getMarkdown());
						articleTxtService.insert(txt);
					}
					continue items;
				}
				keys:for (String key : keys) {
					String value = MapUtils.getString(map, key);
					if(item.getField().equals(key) && StringUtils.isNotBlank(value)) {
						ArticleAttr attr = new ArticleAttr();
						attr.setArticleId(article.getId());
						attr.setName(key);
						attr.setValue(value);
						articleAttrService.insert(attr);
						continue keys;
					}
				}
			}
		}
		ArticleResultDTO resultDTO = new ArticleResultDTO();
		mapper.map(article, resultDTO,Constants.MAPPER_ARTICLE_ID);
		return resultDTO;
	}

}
